package ss.pku.jsa.type.inference;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class TypeClosureUtils {
	Set<IMethodBinding> methodsToAnalyze = new HashSet();
	Set<MethodKey> methodsAnalyzed = new HashSet();
	Set<ITypeBinding> typesToAnalyze = new HashSet();
	Set<TypeKey> typesAnalyzed = new HashSet();
	private Analysis analysis;

	public static void printCU(ITypeBinding t) {
		IJavaElement j = t.getJavaElement();
		if (j == null) {
			JqualPlugin.printlnLog("typeLog", "*** " + t.getName()
					+ " IJavaElement is " + null);
		} else {
			ICompilationUnit c = (ICompilationUnit) j.getAncestor(5);
			if (c == null)
				JqualPlugin.printlnLog("typeLog", "*** " + t.getName()
						+ " ICompilationUnit is " + null);
			else
				JqualPlugin.printlnLog("typeLog", "*** " + t.getName() + " -> "
						+ c.getElementName());
		}
	}

	public ICompilationUnit findType(ITypeBinding t) {
		IType result = null;
		try {
			Iterator p = this.analysis.projects.iterator();
			do {
				IJavaProject j = (IJavaProject) p.next();
				result = j.findType(t.getQualifiedName());

				if ((result != null) && (result.getCompilationUnit() == null))
					result = null;
				if (result != null)
					break;
			} while (p.hasNext());
		} catch (JavaModelException e) {
			e.printStackTrace();
			throw new RuntimeException("JavaModelException in findType");
		}
		if (result != null) {
			return result.getCompilationUnit();
		}
		return null;
	}

	public void addToAnalyzeSet(IMethodBinding m) {
		Profile.logMemStart("addToAnalyzeSet/new MethodKey");
		MethodKey key = MethodKey.getMethodKey(m);
		Profile.logMemEnd();
		if (this.methodsAnalyzed.contains(key))
			return;
		this.methodsToAnalyze.add(m);
	}

	public void addToAnalyzeSet(ITypeBinding t) {
		Profile.logMemStart("addToAnalyzeSet/new TypeKey");
		TypeKey key = TypeKey.getTypeKey(t);
		Profile.logMemEnd();
		if (this.typesAnalyzed.contains(key))
			return;
		this.typesToAnalyze.add(t);
	}

	static class typeFileMap {
		private Map<TypeKey, ICompilationUnit> typeFileMap = new HashMap();

		public ICompilationUnit add(TypeKey key) {
			if (this.typeFileMap.containsKey(key)) {
				return (ICompilationUnit) this.typeFileMap.get(key);
			}
			return null;
		}
	}
}
